<?php

/*
	This file is part of Mandragon.

    Mandragon is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Mandragon is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Mandragon.  If not, see <http://www.gnu.org/licenses/>.
*/

class InputChecker { 

	private $alerter;

	public function __construct() {
		$this->alerter = new Alerter();
	}

	function set_alerter($alerter) {
		$this->alerter = $alerter;
	}

	function check_input($bool, $str) {
		if (!$bool)  {
			$this->alerter->add_alert($str);
		}
		return $bool ? true : false;
	}

	function check_exists($str, $field_name="") {
		//TODO: internationalise message
		return $this->check_input(strlen(trim($str)) > 0, "Geen invoer voor veld [$field_name]");
	}

	function check_url($str, $field_name="") {
		$matches = (ereg("^https?://", $str)) ? true : false;
		return $this->check_input($matches, "$field_name begint niet met 'http://'");
	}

	function checkExistsAndTags($values, $key, $field_name) { //TODO: correct to naming convention
		return $this->check_exists($values[$key], $field_name) && 
			   $this->check_tags($values[$key], $field_name);
	}

	function checkAnswer($ok, $values, $i) { //TODO: correct to naming convention //TODO: parameter $ok should be removed
		$field = "antwoord #$i";
		$value = $values["answer_$i"];
		$result = $this->check_tags_markup($value, $field);
		$result2 = $this->check_exists($value, $field);
		return $ok && $result && $result2;
	}

	function checkExtension($key, $fileKey, $files)
	{
		require_once('config.inc');
		global $CONFIG;

		preg_match_all("/\.(\w.+)$/", $files[$fileKey]['name'], $matches);
		$exists = in_array($matches[1][0], $CONFIG[$key], false);
		if(!$exists) {
			$this->alerter->add_alert("Bestand heeft ongeldig type (enkel: " . join(", ", $CONFIG[$key]) . ")");
		}
		return $exists;
	}

	function checkLink($ok, $values) { //TODO: correct to naming convention //TODO: parameter $ok should be removed

		$is_valid_body_text = $this->checkBody($values);
		$is_valid_link = $this->check_url($values['link'], "link");
		return $ok && $is_valid_body_text && $is_valid_link;
	}

	function checkBody($values) { //TODO: correct to naming convention
		$ok = $this->check_tags_advanced($values['body'], "tekst");
		return $ok && $this->check_exists($values['body'], "tekst");
	}

	function checkNew($ok, $values) { //TODO: correct to naming convention //TODO: parameter $ok should be removed

		$is_valid_subset_text = $this->check_tags_markup($values['new_subset'], "subset");
		$is_filled_out = $this->check_exists($values['new_subset'], "subset");
		return $ok && $is_valid_subset_text && $is_filled_out;
	}

	function check_chars($text, $field_name="") {
		return $this->check_input(preg_match("/^[a-zA-Z0-9]*$/", $text), "Er zijn voor deze invoer enkel alfanumerieke tekens toegestaan [$field_name]");
	}

	function check_int($text, $field_name="") {
		return $this->check_input(preg_match("/^[0-9]*$/", $text), "Er zijn voor deze invoer enkel cijfers toegestaan [$field_name]");
	}

	function check_email($address, $field_name="") {
		return $this->check_input(ereg("^[-a-z0-9_\.]+@([-a-z0-9_]+\.)+[a-z]+$", strtolower($address)), "Ongeldig email-adres [$field_name]");
	}

	function check_tags($text, $field_name="") {
		//TODO: internationalise message
		return $this->check_input((strip_tags($text) === $text), "Er is voor deze invoer geen HTML toegestaan [$field_name]");
	}

	function check_tag($tag, $text, $field_name="") {
		//TODO: internationalise message
		return $this->check_input(!in_array($tag, $this->get_tags($text)), "Tag '$tag' is niet toegestaan voor dit veld [$field_name]");
	}

	function get_tags($text) {

		$string_parts = explode("<", $text);
		array_shift($string_parts);

		$tags = array();
		while ($part = array_shift($string_parts)) {
			preg_match_all('/^ *(.+?)[ >]/', $part, $matches);

			if($matches[1][0]) {
				array_push($tags, $matches[1][0]);
			}
		}
		return $tags;
	}

	function retrieve_default_tags() {
		$checked_tags = array("table", "font", "blockquote", "center", "h1", "h2", "h3", "h4", 
							  "tr", "td", "ul", "li", "ol", "sup", "sub", "small", "quote", 
							  "dialect", "a", "b", "i", "u");
		return $checked_tags;
	}

	function check_tag_closures($text, $checked_tags = 0) {
		$tags = $this->get_tags($text);
		$ok = 1;
		if (!is_array($checked_tags)) {
			$checked_tags = $this->retrieve_default_tags();
		}

		$occurences = array();
		while ($tag = @array_shift($tags)) {
			
			$closing = ereg("^/", $tag) ? 1 : 0;

			$tag = substr($tag, $closing);

			if (in_array($tag, $checked_tags)) {
				
				if (intval($occurences[$tag]) == 0 and $closing) {
					$ok -= 1;
					//TODO: internationalise
					$this->alerter->add_alert("Afsluitende &lt;{$tag}&gt; tag voor openende");
				}

				$add_value = $closing ? -1 : 1;
				$occurences[$tag] = intval($occurences[$tag]) + $add_value;
			}
		}
		if (is_array($occurences) and count($occurences)) {
			$used_tags = array_keys($occurences);
			while ($tag = array_pop($used_tags)) {
				if ($occurences[$tag] != 0) {
					$ok -= 1;
					$this->alerter->add_alert("Ongelijk aantal openende en sluitende &lt;{$tag}&gt; tags");
					//TODO: internationalise
				}
			}
		}
		return ($ok > 0);
	}

	function check_tags_markup($text, $field_name="") {
		$allowed_tags = array("b", "i", "u", "sub", "sup");
		return $this->check_tags_markup_base($text, $allowed_tags, $field_name);
	}


	function check_tags_advanced($text, $field_name="") {
		$allowed_tags = array("i",  "b",  "u",  "sub",  "sup",  "img",  "a",  "table",  "td",  "tr",  
							  "blockquote",  "quote",  "dialect",  "bullshit",  "font",  "ol",  "ul",  
							  "li",  "small",  "h1",  "h2",  "h3",  "h4",  "center",  "p",  "pre",  
							  "tt",  "br",  "br/",  "hr",  "hr/");
		return $this->check_tags_markup_base($text, $allowed_tags, $field_name);
	}

	function check_date_valid($day, $month, $year, $field_name="") {

		if ($day > 0 && $month > 0 && $month <= 12 && $year >= 1900) {

			$long_months = array(1, 3, 5, 7, 8, 10, 12);
			$short_months = array(4, 6, 9, 11);
			$february = 2;

			if(($month === $february && $day <= 29)
				|| (in_array($month, $short_months) && $day <= 30)
				|| (in_array($month, $long_months) && $day <= 31)) {
				return true;	
			}
		}

		$this->alerter->add_alert("Ongeldige datum voor invoer [$field_name]");
		return false;
	}

	public function check_mail_input($internalMail)
	{
		return $this->check_exists($internalMail->subject, "onderwerp") && 
			   $this->check_tags($internalMail->subject, "onderwerp") &&
			   $this->check_exists($internalMail->body, "tekst") &&
			   $this->check_tags_advanced($internalMail->body, "tekst") &&
			   $this->check_tag_closures($internalMail->body);
	}

	function check_date_future($day, $month, $year, $field_name="") {

		if (!$this->check_date_valid($day, $month, $year, $field_name)) {
			return false;
		}

		$date_to_check = mktime(0, 0, 0, $month, $day, $year);
		$current_date = mktime(0, 0, 0, date('n', time()), date('j', time()), date('Y', time()));

		if ($date_to_check > $current_date) {
			return true;
		}
			
		$this->alerter->add_alert("Datum '$day/$month/$year' valt in het verleden [$field_name]");
		return false;
	}

	function check_time($hours, $mins, $field_name="") {
		if ($hours < 0 or $hours > 23 or $mins < 0 or $mins > 59) {
			$this->alerter->add_alert("Tijdstip $hours:$mins is niet geldig als invoer [$field_name]");
			return false;
		}
		return true;
	}

	private function check_tags_markup_base($text, $allowed_tags, $field_name="") {
		$tags = $this->get_tags($text);
		$are_tags_closed_and_allowed = $this->check_tag_closures($text);
		while ($tag = @array_pop($tags)) {
			$stripped_tag = strtolower(preg_replace("/^\//", "", $tag));
			if(!in_array($stripped_tag, $allowed_tags)) {
				$this->alerter->add_alert("tag '$tag' wordt niet herkend of toegelaten voor deze invoer [$field_name]");
				$are_tags_closed_and_allowed = false;
			}
		}
		return $are_tags_closed_and_allowed;
	}
}
?>
